﻿using System.Reflection;

public class HotReloadPluginManager : IDisposable
{
    private readonly string _pluginPath;
    private readonly FileSystemWatcher _watcher;
    private PluginLoader _loader;
    private bool _isUpdating;

    public event Action<Assembly>? PluginReloaded;
    public event Action<Exception>? ReloadFailed;

    public HotReloadPluginManager(string pluginPath)
    {
        _pluginPath = pluginPath;
        _loader = new PluginLoader();

        // 设置文件监视器
        _watcher = new FileSystemWatcher
        {
            Path = Path.GetDirectoryName(pluginPath)!,
            Filter = Path.GetFileName(pluginPath),
            NotifyFilter = NotifyFilters.LastWrite | NotifyFilters.Size,
            EnableRaisingEvents = true
        };

        _watcher.Changed += OnPluginChanged;
    }

    public Assembly LoadInitialPlugin()
    {
        return _loader.LoadPlugin(_pluginPath);
    }

    private void OnPluginChanged(object sender, FileSystemEventArgs e)
    {
        // 防止重复触发
        if (_isUpdating) return;
        _isUpdating = true;

        // 等待文件释放（确保更新完成）
        Thread.Sleep(500);

        try
        {
            // 卸载旧插件
            _loader.UnloadPlugin();

            // 创建新的加载器实例
            _loader = new PluginLoader();

            // 加载新版本
            var newAssembly = _loader.LoadPlugin(_pluginPath);

            // 通知订阅者
            PluginReloaded?.Invoke(newAssembly);
        }
        catch (Exception ex)
        {
            ReloadFailed?.Invoke(ex);
        }
        finally
        {
            _isUpdating = false;
        }
    }

    public object ExecuteMethod(string typeName, string methodName, params object[] args)
    {
        if (_loader.LoadedAssembly == null)
            throw new InvalidOperationException("Plugin not loaded");

        var type = _loader.LoadedAssembly.GetType(typeName);
        if (type == null)
            throw new TypeLoadException($"Type {typeName} not found");

        var method = type.GetMethod(methodName);
        if (method == null)
            throw new MissingMethodException($"Method {methodName} not found");

        var instance = method.IsStatic ? null : Activator.CreateInstance(type);
        return method.Invoke(instance, args);
    }

    public void ExecutePluginLogic(Assembly pluginAssembly, string MethodName)
    {
        try
        {
            var type = pluginAssembly.GetType($"Method_{MethodName}");
            var method = type.GetMethod("Run");
            var instance = Activator.CreateInstance(type);
            method.Invoke(instance, ["null"]);
        }
        catch (Exception ex)
        {
            Console.WriteLine($"❌ Plugin execution failed: {ex.InnerException?.Message ?? ex.Message}");
        }
    }
    public void Dispose()
    {
        _watcher.Dispose();
        _loader.UnloadPlugin();
    }
}